'''
Created on 04/07/2011

@author: Leandro
'''
from Memory.Paging.Page import Page
from SistemaOperativo.PageTable import PageTable
from Memory.MemoryManager import  MemoryManager
from Memory.Paging.Frame import Frame
import threading

class MMUP(MemoryManager):
    lock = threading.RLock()
    #Se crea mmu con memroia, cpu y un tamanio de marco
    def __init__(self, memory, cpu, frameSize):
        self.memory = memory
        self.cpu = cpu
        self.totalFrames = None
        self.frameSize = frameSize
        self.frameList = []
        #Se carga la memoria con marcos del tamanio pasado por parametro
        self.loadMemoryWithFrames(frameSize)
    
    
    def loadProgram(self, aProgram, pcb):
        self.lock.acquire()
        try:
            aProgramPaged = self.paging(self.frameSize, aProgram)
            for page in aProgramPaged:
                emptyFrame = self.emptyFrame()
                emptyFrame.page = page
                pcb.pageTable.pageFrame[page.pageNumber] = emptyFrame.position
                self.swappIn(page)
        finally:
            self.lock.release()
    
    
    def unloadProgram(self, aProgram, pcb):
        self.lock.acquire()
        try:
            for pageNumber in pcb.pageTable.__iter__():
                position = pcb.pageTable[pageNumber].position
                frame = self.frameList[position]
                frame.page = None
                pcb.pageTable = PageTable()
                self.swapOut(aProgram.getInstructionList())
        finally:
            self.lock.release()
            
            
    def swapOut(self, instructionList):
        for instruction in instructionList:
            self.memory.list.__delitem__(instruction)
                
                            
    def loadMemoryWithFrames(self, frameSize):
        i = 0
        while i < (self.memory.getLength() / frameSize):
            self.frameList.append(Frame(frameSize, i))
            i = i + 1
    
    
    def swappIn(self, aPage):
        for instruction in aPage.instructions:
            aPage.baseRegistry = self.memory.loadInstruction(instruction)
    
    #Metodo que asigna marcos a la memoria, de esta manera la memoria queda dividida en marcos
    #los cuales poseen celdas
    def divideMemory(self, frameSize):
        i = 0
        while(len(self.frameList) < self.memory.getLength()/self.frameSize):
            self.frameList.append(Frame(frameSize, i))
            i = i + 1 
        
    #Pagina un programa con el tamanio de marco de la memoria
    def paging(self, frameSize, aProgram):
        n = 0
        aProgramPaged = []
        currentPage = Page(frameSize, n)
        aProgramPaged.append(currentPage)
        for i in aProgram.getInstructionList():
            if(currentPage.isFull()):
                n = n + 1
                currentPage = Page(frameSize, n)
                aProgramPaged.append(currentPage)
                
            currentPage.addInstruction(i)
            
        return aProgramPaged
    
    #Retorna el primer marco libre de memoria 
    def emptyFrame(self):
        for frame in self.frameList:
            if frame.page == None:
                return frame
        
                    